package com.task;


import com.alibaba.fastjson.JSONObject;
import com.util.MD5Util;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class DownloadTask {

    final String DOWLOAD_URL = "http://tv.52iptv.net:8080/api/v1/getTheme";

    @Value("${download.dir}")
    private String downloadDir ;

    @Autowired
    private RestTemplate restTemplate;   //下载

    @Autowired
    private RedissonClient redissonClient; //分布式锁

    /**
     * 每隔5秒定时执行下面的代码：下载,使用了分步式锁
     */
    @Scheduled(initialDelay = 0, fixedDelay = 5000)
     public void download()
     {
         RLock rLock = redissonClient.getLock("download");
         rLock.lock();
              down();
         rLock.unlock();;
     }

    /**
     * 下载
     */
    public void down()
     {
         String respone = restTemplate.getForObject(DOWLOAD_URL,String.class);
         List servers = getServer(respone); //获取所有服务器列表
         String server = getYouXiaoServer(servers); //判断服务器是否通的
         List  urls = getUrls(server, respone); //获取所有需要下载链接
         download(urls); //开始下载

     }

     /*
     开始下载
      */
    private void download(List<String> urls) {
        for (String url : urls) {
            //得到目录名，目录不存在则创建
            String dir = getDIR(url);
            File fileDir = new File(downloadDir+dir);
            if (fileDir.exists()==false){
                fileDir.mkdirs();
            }
            //得到文件名
            String filename = getFileName(url);
            //得到MD5
            String urlMD5 = getUrlMD5(url);
            //求本地文件的MD5值
            File  file = new File(fileDir,filename);
            String fileMD5 = "";
            try {
                fileMD5 = MD5Util.getFileMD5(file);
            } catch (Exception e) {
            }

            //本地MD5和服务器的MD5不一样，就要下载
            if (fileMD5.equalsIgnoreCase(urlMD5)){
                continue;
            }

            //开始下载
            byte[] data = restTemplate.getForObject(url,byte[].class);
            try {
                Files.write(Paths.get(file.getPath()), data);
            } catch (IOException e) {
                e.printStackTrace();
            }


        }
    }

    /**
     * 得到MD5
     * @param url
     * @return
     */
    private String getUrlMD5(String url) {
        int begin = url.lastIndexOf("?md5=");
        String md5 = url.substring(begin+5);
        return md5;
    }

    /**
     * 得到文件名 最后一个/到最后一个?间的内容
     * @param url
     * @return
     */
    private String getFileName(String url) {
        int begin = url.lastIndexOf("/");
        int end   = url.lastIndexOf("?");
        String fileName = url.substring(begin+1,end);
        return fileName;
    }

    /**
     * 获取可用下载列表
     * @param server  服务器
     * @param respone 要解析字符串
     *
     *                [0-9] 表示数字  \d
     *                [a-z] 表示小写
     *                [A-Z] 表示大写
     *                  .   任意字符
     *                [^0-9] 不是数字
     *                [^\"]  不是引号
     *                ?    0-1
     *                *    0-n
     *                +    1-n
     *
     *                ([a-z|A-Z]+)([0-9]*) 分组 group(1) 就是字母    group(2) 就是数字
     *
     *
     * @return
     */
    private List getUrls(String server, String respone) {
        List list = new ArrayList();
        String regStr = "\"([^\"]*)\"";
        Matcher matcher =Pattern.compile(regStr).matcher(respone); //编译正则表式，然后去匹配字符串中是否满足条件的
        while (matcher.find()) //判断是否找到
        {
            String url = matcher.group(1);  //第1对小括号里面的内容
            if (url.indexOf("?md5=")>0)  //判断地址是否含有?md5=字符串
            {
               if (url.startsWith("./")){ //去掉前面./
                   url = url.substring(2);
               }
               if (url.startsWith("/")){  //去掉前面的/
                   url = url.substring(1);
               }
               String downUrl = server+"/"+url;  //原来的服务器和现在后面拼接
               list.add(downUrl); //添加到list集合
            }
        }

        return list;

    }


    /**
     * 得到服务器列表
     * @param jsonString
     * @return
     */
     public List getServer(String jsonString)
     {

         //把json字符串转json对象
         JSONObject  rootJSONObject = JSONObject.parseObject(jsonString);
         //取 data-->SERVER--["",""]
         List list = rootJSONObject.getJSONObject("data").getObject("SERVER",List.class);
         return list;
     }

    /**
     * 获取可用的服务器
     * @param list  服务器列表
     * @return 可用的服务器地址
     */
     public String getYouXiaoServer(List<String> list){
         for (String url : list)
         {
             try {
                 String newURL = url+"/img/image.png";
                 String response = restTemplate.getForObject(newURL,String.class);
                 return url;
             } catch (RestClientException e) {

             }
         }
         return null;

     }

    /**
     * 获取目录名
     * @param url
     * @return
     */
     String getDIR(String url)
     {
         int begin = url.indexOf("/",7);//从第7个位置开始，第1次出现的/
         int end  = url.lastIndexOf("/"); //最后一个/
         String dir = url.substring(begin,end); //截取字符串
         return dir;
     }
}
